home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / grafik / raytracing / rayshade-4.0.6.3 / libray / libsurf / surfshade.c < prev   
C/C++ Source or Header  |  1994-08-09  |  6KB  |  202 lines

  1. /*
  2.  * surfshade.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * surfshade.c,v 4.1 1994/08/09 08:01:46 explorer Exp
  17.  *
  18.  * surfshade.c,v
  19.  * Revision 4.1  1994/08/09  08:01:46  explorer
  20.  * Bump version to 4.1
  21.  *
  22.  * Revision 1.1.1.1  1994/08/08  04:52:13  explorer
  23.  * Initial import.  This is a prerelease of 4.0.6enh3, or 4.1 possibly.
  24.  *
  25.  * Revision 4.0.1.2  92/01/10  14:08:28  cek
  26.  * patch3: Fixed additional composition problems.
  27.  * 
  28.  * Revision 4.0.1.1  91/12/13  11:54:51  cek
  29.  * patch3: Fixed ordering of world/model xform composition.
  30.  * patch3: Geometric normal now transformed correctly.
  31.  * 
  32.  * Revision 4.0  91/07/17  14:41:15  kolb
  33.  * Initial version.
  34.  * 
  35.  */
  36. #include "libobj/geom.h"
  37. #include "surface.h"
  38.  
  39. /*
  40.  * Compute surface properties from given hitlist
  41.  * Returns TRUE if ray is entering object, FALSE otherwise.
  42.  */
  43. int
  44. ComputeSurfProps(hitlist, ray, pos, norm, gnorm, surf, smooth)
  45. HitList *hitlist;    /* Hit information (path through DAG) */
  46. Ray *ray;        /* Ray in world space */
  47. Vector *pos;        /* Intersection point */
  48. Vector *norm, *gnorm;    /* shading normal, geometric normal (return values) */
  49. Surface *surf;        /* Copy of surface to use, texture-modified */
  50. int *smooth;
  51. {
  52.     HitNode *hp;
  53.     int i;
  54.     Ray rtmp;
  55.     Geom *prim, *obj;
  56.     Float k, kp;
  57.     int texturing, transforming, entering;
  58.     Trans prim2model, world2model;
  59.  
  60.     hp = hitlist->data;
  61.     prim = hp->obj;
  62.  
  63.     /*
  64.      * Compute point of intersection in "primitive space".
  65.      */
  66.     VecAddScaled(hp->ray.pos, hp->dist, hp->ray.dir, pos);
  67.  
  68.     /*
  69.      * Find normal to primitive at point of intersection.
  70.      */
  71.     *smooth = PrimNormal(prim, pos, norm, gnorm);
  72.  
  73.     texturing = transforming = FALSE;
  74.  
  75.     /*
  76.      * Walk down hit list, constructing world<-->primitive transformation
  77.      * and determining if we need to perform texture mapping.
  78.      * The last node is the World node, which cannot be textured or
  79.      * transformed, so we skip it.
  80.      */
  81.     for (i = 0, hp = hitlist->data; i < hitlist->nodes -1; hp++, i++) {
  82.         obj = hp->obj;
  83.         texturing = texturing || obj->texture;
  84.         if (hp->dotrans) {
  85.             /*
  86.              * Here we're actually computing prim2world.
  87.              * When finished, we invert it.
  88.              */
  89.             if (transforming) {
  90.                 TransCompose(&world2model, &hp->trans,
  91.                     &world2model);
  92.             } else {
  93.                 TransCopy(&hp->trans, &world2model);
  94.                 transforming = TRUE;
  95.             }
  96.         }
  97.     }
  98.  
  99.     /*
  100.      * Determine if we're entering or exiting the surface,
  101.      * flipping surface normals if necessary.
  102.      */
  103.     k = dotp(&hitlist->data[0].ray.dir, norm);
  104.     if (*smooth) {
  105.         /*
  106.          * If gnorm and shading norm differ and
  107.          * their dot products with the ray have
  108.          * different signs, use the geometric normal
  109.          * instead, ala Snyder & Barr's paper.
  110.          */
  111.         kp = dotp(&hitlist->data[0].ray.dir, gnorm);
  112.         if (k <= 0. && kp > 0. || k >= 0. && kp < 0.)
  113.             k = kp;
  114.     }
  115.  
  116.     if (k > 0.) {
  117.         /* flip normals */
  118.         VecScale(-1., *gnorm, gnorm);
  119.         VecScale(-1., *norm, norm);
  120.         /*
  121.          * Normal indicates that we're exiting.
  122.          * Only set entering to TRUE if csg has indicated
  123.          * that the ray is, indeed, entering.
  124.          */
  125.         entering = (hitlist->data[0].enter == ENTERING);
  126.     } else {
  127.         /*
  128.          * Normal indicates that we're entering.
  129.          * Set entering flag as such unless csg has
  130.          * told us that we're exiting.
  131.          */
  132.         entering = !(hitlist->data[0].enter == EXITING);
  133.     }
  134.         
  135.     /*
  136.      * If there are no transformations, then world2model is identity.
  137.      */
  138.     if (!transforming)
  139.         TransInit(&world2model);
  140.     /*
  141.      * If we're not performing texturing, we simply need to compute
  142.      * the normal and point of intersection to world space.
  143.      */
  144.     if (!texturing) {
  145.         /*
  146.           * At this point 'world2model' is really 'prim2world'.
  147.          */
  148.         if (transforming) {
  149.             NormalTransform(norm, &world2model.itrans);
  150.             NormalTransform(gnorm, &world2model.itrans);
  151.             VecAddScaled(ray->pos,
  152.                      hitlist->data[hitlist->nodes -1].dist,
  153.                      ray->dir, pos);
  154.         }
  155.         return entering;
  156.     }
  157.     /*
  158.      * world2model currently transforms from primitive to world space.
  159.      * Invert it to get transformation from world to primitive space.
  160.      */
  161.     TransInvert(&world2model, &world2model);
  162.     TransInit(&prim2model);
  163.     rtmp = hitlist->data[0].ray;
  164.     /*
  165.      * Walk down hitlist (from primitive up to World object),
  166.      * transforming hit point and shading normal and applying textures.
  167.      * Note that the texturing routines want gnorm in object space,
  168.      * so we don't transform the geometric normal until texturing
  169.      * is complete.
  170.      */
  171.     for (hp = hitlist->data, i = 0; i < hitlist->nodes -1; i++, hp++) {
  172.         obj = hp->obj;
  173.         if (hp->dotrans) {
  174.             NormalTransform(norm, &hp->trans.itrans);
  175.             if (texturing) {
  176.                 /*
  177.                  * Compose prim<-->model and world<-->model
  178.                  * with current transformation.
  179.                  */
  180.                 TransCompose(&prim2model, &hp->trans,
  181.                     &prim2model);
  182.                 TransCompose(&world2model, &hp->trans,
  183.                     &world2model);
  184.                 /*
  185.                  * Transform point and ray to model space.
  186.                  */
  187.                 PointTransform(pos, &hp->trans.trans);
  188.                 (void)RayTransform(&rtmp, &hp->trans.trans);
  189.             }
  190.         }
  191.         /*
  192.          * Apply textures
  193.          */
  194.         if (obj->texture)
  195.             TextApply(obj->texture, prim, &rtmp, pos, norm,
  196.                 gnorm, surf, &prim2model, &world2model);
  197.     }
  198.     /* Transform geometric normal from object to world space. */
  199.     NormalTransform(gnorm, &world2model.trans);
  200.     return entering;
  201. }
  202.